import os from 'os';
import fs from 'fs';
import path from 'path';
import * as http from 'http';
import * as https from 'https';
import { app, Config, startApp, container, hredis } from '../app';
import { makeLabelLogger, llog } from '../util/logger';
import * as express from 'express';

import { bootEvent } from '../boot';
import { ISyncService, tsISyncService } from '../service/api/sync';

// 加载各种自注册模块
import '../util/asset';
import './syncuser';
import './rpcgate';

let httpServer: http.Server;
let httpsServer: https.Server;

export let startUserServer = function() {
	startApp();
	bootEvent.addListener('appInit', async () => {
		setupStaticServe(app);
		startHttpServer();
		startHttpsServer();
		startUDP();
		startSync();

		bootEvent.emit('appStart');
	});
};

let startSync = () => {
	// 启动同步服务
	let ss = container.get<ISyncService>(tsISyncService);
	ss.start(Config.getRedis(), Config.getSyncRedis());

	// 定时心跳
	let dtHeart = Config.getSyncHeartbeat();
	let sendHeart: () => void;
	sendHeart = async () => {
		ss.postMessage({ type: 'heartbeat', time: new Date(Date.now()).toLocaleString() });

		let dtNext = await hredis.get('config:dtHeart');
		dtHeart = parseInt(dtNext) || dtHeart;
		setTimeout(sendHeart, dtHeart);
	};
	sendHeart();
};

let startHttpServer = () => {
	httpServer = app.listen(Config.getHttpPort(), '0.0.0.0');
	httpServer.on('error', e => {
		if (/listen EADDRINUSE/.test(e.message)) {
			console.log('ignore temp addr error');
		} else {
			console.log('server error', e.message);
		}
	});
	llog('* api server is listening on port : ' + Config.getHttpPort());
};
let startHttpsServer = () => {
	let sslPath = path.resolve('./ssl');
	if (fs.existsSync(sslPath)) {
		try {
			const privateKey = fs.readFileSync(`${sslPath}/server-key.pem`, 'utf8');
			const certificate = fs.readFileSync(`${sslPath}/server-cert.pem`, 'utf8');
			const credentials = { key: privateKey, cert: certificate };
			const port = Config.getHttpsPort();
			httpsServer = https.createServer(credentials, app);
			httpsServer.listen(port, '0.0.0.0');
			llog('* https server is listening on port : ' + port);
		} catch (e) {
			llog(' no https server ');
		}
	} else {
		llog(' no https server ');
	}
};

let startUDP = () => {
	let dgram = require('dgram');
	let udpServer = dgram.createSocket('udp4');
	let hn = os.hostname();
	let isInDocker = fs.existsSync('/.dockerenv');
	if (isInDocker) hn = 'docker:' + hn;

	try {
		udpServer.on('listening', function() {
			let address = udpServer.address();
			llog(`* UDP Server listening on ${hn} ${address.address}:${address.port}`);
		});

		udpServer.on('message', function(message, remote) {
			llog('udp recv', remote.address + ':' + remote.port + ' - ' + message);
			let reply = hn;
			udpServer.send(reply, 0, reply.length, remote.port, remote.address);
		});

		udpServer.bind(Config.getUDPPort(), '0.0.0.0');
	} catch (e) {
		console.log(e);
	}
};

let setupStaticServe = async function(app) {
	let serveIndex = require('serve-index');
	let testDir = process.env.HOME + '/test';
	app
		.use('/static', express.static(Config.getStaticDirectory()))
		.use('/static', serveIndex(Config.getStaticDirectory(), { icons: true, view: 'details' }))
		.use('/html', express.static('./html'));
};
